home *** CD-ROM | disk | FTP | other *** search
/ Internet Publisher's Toolbox 2.0 / Internet Publisher's Toolbox.iso / internet / ntserver / wtsource / waisserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-16  |  31.5 KB  |  1,067 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.
  4.    5.29.90  Harry Morris, morris@think.com
  5. */
  6.  
  7. /* Copyright (c) CNIDR (see ../COPYRIGHT) */
  8.  
  9.  
  10. /* this file is a server process for a unix machine that takes input from 
  11.    standard in or from a socket and searches the local search engine on the 
  12.    unix box.
  13.    originally written by harry morris.
  14.    modified by brewster kahle. 7/90
  15.    6.xx.90  Brewster - initial implementation of stdio interface
  16.    7.xx.90  Patrick Bray - support for headers and forking processes
  17.    90.07.31 Ephraim - support for logging 
  18.  
  19.    91.03.03     Jonathan - set searchLog to log_out.
  20.    91.05.23 Jonathan - added fork process for indexer.
  21.                            Fixed version display so it exits.
  22.    91.05.25     Jonathan - added setuid.
  23.    
  24.    Tue Jul  9 12:11:02 1991 -- Michael Haberler mah@wu-wien.ac.at
  25.  
  26.                 Added semi-intelligent INFO database indexing (only done if
  27.         any of the .src files is newer than INFO.dct)
  28.         
  29.         Locking against multiple concurrent INFO rebuilds if 
  30.         running under inetd
  31.  
  32.         Use scandir() for directory operations
  33.  
  34.         Works under inetd as well as standalone. Here are my inetd.conf
  35.         entries (not the missing userid in the Ultrix inetd.conf!):
  36.  
  37.    hpux 7.0/800, Interactive/386 2.2.1:
  38.     z3950 stream tcp nowait root /usr/local/etc/waisserver waisserver -s \
  39.         -d /usr/logins/mah/wais-sources
  40.  
  41.    Ultrix 4.1:
  42.     z3950 stream tcp nowait /usr/local/etc/waisserver waisserver -s \
  43.         -d /usr/logins/mah/wais-sources
  44.  
  45.    Also, add the next line to /etc/services, and tickle your YP server:
  46.     z3950           210/tcp         # wide area information server (wais)
  47.  
  48.  * $Log: waissrch.c,v $
  49.  * Revision 1.1  1994/03/29  14:11:07  shangjiej
  50.  * Initial revision
  51.  *
  52.  * Revision 1.3  93/07/21  18:52:39  warnock
  53.  * Renamed from server.c.
  54.  * Added STELAR-specific patches
  55.  * 
  56.  * Revision 1.2  93/07/01  19:19:53  warnock
  57.  * gethostname -> mygethostname
  58.  * 
  59.  * Revision 1.1  1993/02/16  15:05:35  freewais
  60.  * Initial revision
  61.  *
  62.  * Revision 1.48  92/05/10  14:47:39  jonathan
  63.  * Update for release.
  64.  * 
  65.  * Revision 1.47  92/05/06  17:34:01  jonathan
  66.  * Changed auto-indexing of .src files to use filename_finish_header_function.
  67.  * 
  68.  * Revision 1.46  92/05/04  17:18:32  jonathan
  69.  * Fixed use of merge_pathname in creating INFO database.
  70.  * 
  71.  * Revision 1.45  92/04/28  15:19:18  jonathan
  72.  * Added decoding of IP address to DNS name in init message handler.
  73.  * 
  74.  * Revision 1.44  92/03/26  18:26:41  jonathan
  75.  * Added extra arguments to index_text_file call.
  76.  * 
  77.  * Revision 1.43  92/03/07  19:41:47  jonathan
  78.  * Added IBM defines, courtesy mycroft@hal.gnu.ai.mit.edu,
  79.  * 
  80.  * Revision 1.42  92/03/05  07:07:58  shen
  81.  * add two more dummy arguments to call to init_search_engine
  82.  * 
  83.  * Revision 1.41  92/02/27  09:58:50  jonathan
  84.  * Put back in setting of core limit to max value, when SET_LIMIT is defined.
  85.  * 
  86.  * Revision 1.40  92/02/24  10:07:41  jonathan
  87.  * Removed reporting functions.
  88.  * 
  89.  * Revision 1.39  92/02/21  12:27:15  jonathan
  90.  * Changed logging of segmentation violation and bus errors to mark log with
  91.  * an error code, and close code.
  92.  * 
  93.  * Revision 1.38  92/02/21  11:00:45  jonathan
  94.  * Added wais_log_level
  95.  * 
  96.  * Revision 1.37  92/02/19  10:16:25  jonathan
  97.  * Added build_catalog to auto-indexer.
  98.  * 
  99.  * Revision 1.36  92/02/16  12:33:21  jonathan
  100.  * Removed code refering to NOINETNTOA, since we should use inet_ntoa.
  101.  * 
  102.  * Revision 1.35  92/02/16  12:05:18  jonathan
  103.  * Added code for GCC incompatibility in inet_ntoa (passing structure as
  104.  * pointer).
  105.  * 
  106.  * Revision 1.34  92/02/14  09:07:34  jonathan
  107.  * Set MAXNAPTIME to 0 so it won't sleep.  Changed the WLOG_ERROR to
  108.  * WLOG_WARNING in the log entry.
  109.  * 
  110.  * Revision 1.33  92/02/12  13:44:20  jonathan
  111.  * Added "$Log" so RCS will put the log message in the header
  112.  * 
  113.  * 
  114.  */
  115.  
  116. #define SERVER_DATE "Fri April 9 1993"
  117.  
  118. #ifndef lint
  119. static char *RCSid = "$Header: /archives/stelar/src/freeWAIS/freeWAIS-0.2/ir/RCS/waisserver.c,v 1.3 93/07/21 18:52:39 warnock Exp $";
  120. #endif
  121.  
  122. #define INFO_DICT    "INFO.dct"
  123. #ifdef WIN32
  124. /* char LOCKFILE[MAX_PATH+1]; move further down as MAX_PATH undefined here */
  125. #define NAPTIME     1000        /* milliseconds */
  126. #else
  127. #define LOCKFILE    "/tmp/INFO.lock" /* while re-indexing INFO */
  128. #define NAPTIME     1            /* seconds */
  129. #endif
  130. #define MAXNAPTIME  0       /* Don't wait, just go on. */
  131.  
  132. #include "server.h"
  133. #include "sockets.h"
  134. #include <sys/types.h>
  135. #include <sys/stat.h>
  136. #ifdef ULTRIX
  137. /* #include <sys/file.h> */
  138. #include <fcntl.h>
  139. #else
  140. #ifdef _IBMR2
  141. #include <fcntl.h>
  142. #else /* ! _IBMR2 */
  143. #ifdef USG
  144. #include <sys/fcntl.h>
  145. #else
  146. #ifdef WIN32
  147. #include <fcntl.h>
  148. #include <io.h>
  149. #else
  150. #include <sys/file.h>
  151. #endif /* WIN32 */
  152. #endif
  153. #endif /* _IBMR2 */
  154. #endif /* else ultrix */
  155. #ifdef SYSV         
  156. #define SIGCHLD SIGCLD
  157. #endif
  158.  
  159. #ifdef sgi
  160. #include <sys/signal.h>
  161. #else
  162. #include <signal.h>
  163. #endif
  164.  
  165. #include <string.h>
  166. #include "irdirent.h"
  167. #include "panic.h"
  168. #include "ustubs.h"
  169. #include "transprt.h"
  170. #include "wmessage.h"
  171. #include "ir.h"
  172. #include "wprot.h"
  173. #include "cutil.h"
  174. #include "futil.h"
  175. #include "irext.h"
  176. #include "irsearch.h"
  177.  
  178. /* to create the INFO index */
  179. #include "irtfiles.h"
  180. #include "irfiles.h"
  181. #include "irhash.h"
  182. #include "version.h"
  183.  
  184. #ifdef WIN32
  185. char LOCKFILE[MAX_PATH+1];
  186. void stop_list_file(char *filename);
  187. boolean server_security(char *index_directory, char *database_name);
  188. #endif
  189. #ifdef DEBUG
  190.   FILE *debug_log;
  191. #endif
  192.  
  193. static long bufferSize = BUFSZ; /* how much we are using
  194.                                    (we get one of these per process) */
  195.  
  196.  
  197. extern char host_name[255], host_address[255];
  198.  
  199. /* Bitmap association table -- LEB/HSTX 8/5/92 */
  200. #ifdef STELAR
  201. #define LOOKUP_TABLE /archives/stelar/abs/wais/bitmap.table
  202.  
  203. char *bitmap_table = "LOOKUP_TABLE";
  204.  
  205. /* char *bitmap_table = "/archives/stelar/abs/wais/bitmap.table"; */
  206. #endif /* STELAR */
  207.  
  208. /*---------------------------------------------------------------------------*/
  209. #ifdef WIN32
  210. #define TIMEOUT_LENGTH 3600000 /* one hour timeout. */
  211. #else
  212. #define TIMEOUT_LENGTH 3600 /* one hour timeout. */
  213. #endif
  214. #define IDLE_TIME "1 hour"
  215.  
  216. void
  217. serve_client(in,out, index_directory)
  218. FILE* in;
  219. FILE* out;
  220. char *index_directory;
  221.   char buf[BUFSZ];      /* contains the message and header */
  222.   char *bufPtr ;        /* points at the begining of the z3950 */
  223.   long size;            /* bytes in the z3950 message */
  224.   WAISMessage header;       /* for storing the header */
  225.   long i;
  226.   long bytesLeft;
  227.   long nextChar;
  228. #ifndef WIN32
  229.   struct itimerval new, old;
  230.  
  231.   new.it_interval.tv_sec = 0;
  232.   new.it_interval.tv_usec = 0;
  233.   new.it_value.tv_sec = TIMEOUT_LENGTH;
  234.   new.it_value.tv_usec = 0;
  235.  
  236.   getitimer(ITIMER_REAL, &old);
  237.   while (TRUE)
  238.     {
  239.       /* try to read the header */
  240.       for (i = 0; i < HEADER_LENGTH; i++)
  241.     { 
  242.       setitimer(ITIMER_REAL, &new, NULL);
  243.       nextChar = fgetc(in);
  244.       if (nextChar == EOF)  /* my connection exited, so will I */
  245.         { 
  246.           return;
  247.         }
  248.       else
  249.         buf[i] = (char)nextChar;
  250.     }
  251.  
  252.       setitimer(ITIMER_REAL, &old, NULL);
  253. #else
  254.   UINT timerid;
  255.   while (TRUE)
  256.     {
  257.       /* try to read the header */
  258.       timerid = SetTimer(NULL, 0, TIMEOUT_LENGTH, NULL);
  259.       for (i = 0; i < HEADER_LENGTH; i++)
  260.       { 
  261.         nextChar = fgetc(in);
  262.         if (nextChar == EOF)  /* my connection exited, so will I */
  263.         { 
  264.             KillTimer(NULL, timerid);
  265.             return;
  266.         } else
  267.           buf[i] = (char)nextChar;
  268.       }
  269.       KillTimer(NULL, timerid);
  270. #endif /* WIN32 */
  271.  
  272.       /* parse the header */
  273.       readWAISPacketHeader(buf,&header);
  274.  
  275.       /* make sure we have the right version.  
  276.      If we dont, we dont know what to do. */
  277.       if (header.hdr_vers > HEADER_VERSION)
  278.     panic("Incompatable header versions (Current version: %c, supplied version: %c.", 
  279.           HEADER_VERSION, header.hdr_vers) ;
  280.  
  281.       /* determine the size of the z3950 message */
  282.       {
  283.     char length_array[11];
  284.     strncpy(length_array, header.msg_len, 10);
  285.     length_array[10] = '\0';
  286.     size = atol(length_array);
  287.       }
  288.  
  289.       /* set bufPtr to start the z3950 message */
  290.       bufPtr = buf + HEADER_LENGTH ;
  291.  
  292.       /* read the z3950 message */
  293. #ifdef WIN32
  294.       timerid = SetTimer(NULL, 0, TIMEOUT_LENGTH, NULL);
  295.       for (i = 0; i < size ; i++) {
  296.           buf[i + HEADER_LENGTH] = (char)fgetc(in) ;
  297.       }
  298.       KillTimer(NULL, timerid);
  299. #else
  300.       for (i = 0; i < size ; i++) {
  301.     setitimer(ITIMER_REAL, &new, NULL);
  302.     buf[i + HEADER_LENGTH] = (char)fgetc(in) ;
  303.       }
  304. #endif
  305.  
  306.       rewind(in);
  307.  
  308.       /* decode the z3950 if necessary */
  309.       transportDecode((long)header.encoding,bufPtr,&size);
  310.      
  311.       /* XXX handle compression options */
  312.  
  313.       /* process it the z3950 */
  314.       bytesLeft = bufferSize;
  315.  
  316.       size = interpret_buffer(bufPtr,size,bufPtr,bytesLeft,
  317.                   &bufferSize,(long)header.hdr_vers,
  318.                   index_directory); 
  319.  
  320.       /* re-encode the message if necessary */
  321.       transportCode((long)header.encoding,bufPtr,&size); 
  322.  
  323.       /* XXX handle compression options */
  324.  
  325.       /* write the new header */
  326.       writeWAISPacketHeader(buf,size,
  327.                 (long)header.msg_type,header.server,
  328.                 (long)header.compression,(long)header.encoding,
  329.                 (long)header.hdr_vers);
  330.  
  331.       /* write the whole response to the output file */
  332.       for (i = 0; i < size + HEADER_LENGTH; i++)
  333.     fputc(buf[i],out) ;
  334.  
  335.       fflush(out);      /* flush any file buffers */
  336.       rewind(out);      /* reset the file for read */
  337.  
  338.     }
  339. }
  340.  
  341. /*---------------------------------------------------------------------------*/
  342.  
  343. #ifndef ISC
  344. #ifndef LINUX
  345. static void breakKey _AP((long s1,long s2,struct sigcontext* s3,char* s4));
  346. #endif
  347. #endif
  348.  
  349. static void
  350. breakKey (s1,s2,s3,s4)
  351. long s1;
  352. long s2;
  353. struct sigcontext *s3;
  354. char *s4;
  355. {
  356.   if(0 != finished_search_engine())
  357.     panic("unable to close search engine");
  358.   panic ("got a ^c");
  359.   signal (SIGINT, (void *)breakKey);
  360. }
  361.  
  362. /*---------------------------------------------------------------------------*/
  363.  
  364. void
  365. childhandler(sig, code, scp, addr)
  366. long sig, code;
  367. struct sigcontext *scp;
  368. char *addr;
  369. {
  370. #ifndef WIN32
  371.   wait(NULL);           /* give the kid a decent burial */
  372.   signal (SIGCHLD, childhandler);  /* Dave Judd - IRIX requires resetting signal */
  373. #endif
  374. }
  375.  
  376. /*---------------------------------------------------------------------------*/
  377.  
  378. void
  379. alarmhandler(sig, code, scp, addr)
  380. long sig, code;
  381. struct sigcontext *scp;
  382. char *addr;
  383. {
  384.   waislog(WLOG_HIGH, WLOG_CLOSE,
  385.       "Server idle longer %s. Closing server and exiting.", IDLE_TIME);
  386.   if(0 != finished_search_engine())
  387.     panic("unable to close search engine");
  388.   exit(0);
  389. }
  390.  
  391. /*---------------------------------------------------------------------------*/
  392.  
  393. void
  394. seghandler(sig, code, scp, addr)
  395. long sig, code;
  396. struct sigcontext *scp;
  397. char *addr;
  398. {
  399.   waislog(WLOG_HIGH, WLOG_ERROR, "Segmentation violation.");
  400.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  401. #ifdef DUMPCORE
  402.     abort();
  403. #else
  404.   exit(-1);
  405. #endif
  406. }
  407.  
  408. /*---------------------------------------------------------------------------*/
  409.  
  410. void
  411. bushandler(sig, code, scp, addr)
  412. long sig, code;
  413. struct sigcontext *scp;
  414. char *addr;
  415. {
  416.   waislog(WLOG_HIGH, WLOG_ERROR, "Bus error.");
  417.   waislog(WLOG_HIGH, WLOG_CLOSE, "Bummer. Closing server and exiting.");
  418. #ifdef DUMPCORE
  419.     abort();
  420. #else
  421.   exit(-1);
  422. #endif
  423. }
  424.  
  425. /*---------------------------------------------------------------------------*/
  426.  
  427. #ifndef WIN32
  428. #include <pwd.h>
  429.  
  430. int finduid(name)
  431. char *name;
  432. {
  433.   struct passwd *pwent;
  434.  
  435.   if ((pwent = getpwnam(name)) == NULL) {
  436.     return -1;
  437.   }
  438.  
  439.   return(pwent->pw_uid);
  440. }
  441. #endif
  442.  
  443. static  char *index_dir = NULL;
  444. static  time_t info_change_time;
  445. static  int indexing_needed = 0;
  446. static  char *info_dict = INFO_DICT;
  447.  
  448. extern int alphasort();
  449.  
  450. /* selecttion function for scandir()
  451.  * trigger on ".src" extension, regular file, and != "INFO.src"
  452.  * Indexing is needed if any of the .src files is younger than 
  453.  * INFO.dct
  454.  */
  455. static int
  456. srcfiles(e)
  457.     struct dirent *e;
  458. {
  459. #ifndef WIN32
  460.     struct stat sb;
  461.     char *lastdot = strrchr(e->d_name,'.');
  462.     int candidate;
  463.  
  464.     candidate = lastdot && 
  465.           (stat(merge_pathnames(e->d_name,index_dir), &sb) >= 0) && 
  466.           ((sb.st_mode & S_IFMT) == S_IFREG) &&
  467.           !strcmp(lastdot,source_ext) && 
  468.           strcmp(e->d_name,info_dict); /* whew */
  469.  
  470.         if (candidate) {
  471.         indexing_needed |= (sb.st_mtime > info_change_time);
  472.         return 1;
  473.     }
  474. #endif
  475.     return 0;
  476. }
  477.  
  478.  
  479. /*---------------------------------------------------------------------------*/
  480.  
  481. #ifdef SET_LIMIT
  482. #include <sys/resource.h>
  483. #endif
  484.  
  485. #ifndef WIN32
  486. #define INDEX_FORK
  487.  
  488. extern char *inet_ntoa ();
  489. #endif
  490. extern char *syslog_name;
  491.  
  492. void
  493. main(argc,argv)
  494. int argc;
  495. char* argv[];
  496. #ifndef WIN32
  497.   FILE *file;
  498. #endif
  499. #ifdef DEBUG
  500.   int i;
  501. #endif
  502.   char *next_argument = next_arg(&argc, &argv), *command_name;
  503.   boolean use_stdio = TRUE;     /* default is true */
  504.   /* char *log_file_name = NULL; */ /* name of file for error output */
  505.   char *uid_name = "root";  /* user id so setuid if root */
  506.   int uid = 0;      /* if not specified, leave as root. */
  507. #ifndef WIN32
  508.   long socket;
  509.   int child_proc;       /* for the child process id */
  510.   int child;
  511. #endif
  512.   long cm_mem_percent = 0;  /* default */
  513.   struct stat statbuf;
  514. #ifndef WIN32
  515.   struct dirent **list;
  516. #endif
  517.   int naptime = 0;
  518.   extern int errno;
  519.   extern char *sys_errlist[];
  520.   extern void filename_finish_header_function();
  521.   dataopsrec    dataops;  
  522.   
  523. #ifdef SET_LIMIT
  524.   struct rlimit rlp;
  525.  
  526.   getrlimit(RLIMIT_CORE, &rlp);
  527.   rlp.rlim_cur = rlp.rlim_max;
  528.   setrlimit(RLIMIT_CORE, &rlp);
  529.   getrlimit(RLIMIT_DATA, &rlp);
  530.   rlp.rlim_cur = rlp.rlim_max;
  531.   setrlimit(RLIMIT_DATA, &rlp);
  532. #endif
  533.  
  534. #ifdef WIN32
  535.   /* Turn stdout buffering off */
  536.   setvbuf(stdout,NULL,_IONBF,0);
  537.   /* We need binary mode for standard input and output -- no translation CR-LF*/
  538.   _setmode(_fileno(stdin), _O_BINARY);
  539.   _setmode(_fileno(stdout), _O_BINARY);
  540. #endif /*WIN32 */
  541.  
  542. /* dgg -- must duplicate mods to waisindex.c, here is mini-build of INFO.src */
  543.   dataops.separator_function= NULL;
  544.   dataops.header_function= NULL;
  545.   dataops.date_function= NULL;
  546.   dataops.finish_header_function= filename_finish_header_function;
  547.   dataops.type= "WSRC";
  548.   dataops.wordDelimiter= wordbreak_notalnum;
  549.   dataops.addseparatorwords= false;
  550.   dataops.extraheaderweight= true;
  551.   dataops.repeat_weight= 1;
  552.   dataops.minwordlen= 2;
  553.   stop_list_file("\0");
  554.   gDelimiters[0]= '\0';  
  555.   wordDelimiter= wordbreak_notalnum;   
  556. /* dgg -- end new inits */                       
  557.  
  558. #ifdef DEBUG
  559.   /*DebugBreak();/**/
  560.   debug_log = fopen("waisserv.log", "a");
  561.   fprintf(debug_log, "WAISSERV has been called with following arguments argc = %d:\n", argc);
  562.   for (i = 0; i < argc; i++)
  563.     fprintf(debug_log, "argv[%d] = %s\n", i, argv[i]);
  564. #endif  
  565.   tcp_port = 210;           /* tcp_port to use */
  566.   command_name = next_argument;
  567. #ifdef WIN32
  568.   syslog_name = (syslog_name = (char *)strrchr(command_name, '\\')) ? (syslog_name + 1) : command_name;
  569. #else
  570.   syslog_name = (syslog_name = (char *)rindex(command_name, '/')) ? (syslog_name + 1) : command_name;
  571. #endif
  572.   host_name[0] = 0;
  573.   host_address[0] = 0;
  574.  
  575.   server_name = s_malloc(255);
  576.   mygethostname(server_name, 255);
  577.  
  578. #ifdef WIN32
  579.   wais_pid = 0;
  580. #else
  581.   wais_pid = getpid();
  582. #endif
  583.  
  584. #ifdef DEBUG
  585.   fprintf(debug_log, "command_name = %s\n", command_name);
  586. #endif      
  587.  
  588.   if (!strcmp(command_name, "waisserver.d")) {
  589.     struct sockaddr_in source;
  590.     int sourcelen;
  591.  
  592.     sourcelen = sizeof(struct sockaddr_in);
  593.  
  594. #ifdef WIN32
  595.     if (!getpeername(fileno(stdout),(struct sockaddr *)&source,&sourcelen)) {
  596. #else
  597.     if (!getpeername(fileno(stdout),
  598.                      (void *)&source,&sourcelen)) {
  599. #endif
  600.       struct hostent *peer = NULL;
  601.  
  602. #ifdef WIN32
  603.       peer = gethostbyaddr((char *)&source.sin_addr.s_addr, 4, PF_INET);  /* is it right? */
  604. #else
  605. #ifdef __DGUX__
  606.       peer = gethostbyaddr((char *)&source.sin_addr.s_addr, 4, AF_INET);
  607. #else
  608.       peer = gethostbyaddr((void *)&source.sin_addr, 4, AF_INET);
  609. #endif
  610. #endif
  611.       if(peer != NULL) {
  612.     sprintf(host_name, "%s", peer->h_name);
  613.  
  614.     sprintf(host_address, "%s",
  615. #if defined(sparc) && defined(__GNUC__)
  616.         inet_ntoa(&source.sin_addr)
  617. #else
  618.         inet_ntoa(source.sin_addr)
  619. #endif              /* sparc */
  620.         );
  621.     }
  622.     }
  623.     else sprintf(host_address, "Error getting socket: %d, %s.", errno, sys_errlist[errno]);
  624.  
  625.    use_stdio = TRUE;
  626.   }
  627.  
  628.   if (argc == 0){
  629. #ifdef DEBUG
  630.       fprintf(debug_log, "argc = 0\n");
  631. #endif      
  632.  
  633. #ifdef WIN32
  634.     fprintf(stderr,"Usage: %s [-s] [-d directory] [-v] [-e file] [-l level]\n",command_name);
  635. #else
  636.     fprintf(stderr,"Usage: %s [-p [port_number]] [-s] [-d directory] [-u user] [-cmmem number] [-v]\n",
  637.        command_name);
  638.     fprintf(stderr," -p [port] listen to the port.  If the port is supplied, then\n");
  639.     fprintf(stderr,"    that tcp_port number is used.  If it is not supplied \n");
  640.     fprintf(stderr,"    then the Z39.50 port (210) is used.\n");
  641. #endif
  642.     fprintf(stderr," -d directory: means to use the directory as the source of databases.\n");
  643.     fprintf(stderr,"    Defaults to the current directory.\n");
  644. #ifdef WIN32
  645.     fprintf(stderr," -e [file]: set log output to file, or NUL: if not specified.\n");
  646. #else
  647.     fprintf(stderr," -e [file]: set log output to file, or /dev/null if not specified.\n");
  648. #endif
  649.     fprintf(stderr," -l log_level: set log level.  0 means log nothing,\n");
  650.     fprintf(stderr,"    10 [the default] means log everything.\n");
  651.     fprintf(stderr," -s means listen to standard I/O for queries.  This is the default\n");
  652. #ifndef WIN32
  653.     fprintf(stderr," -u user: if started as root, setuid to user after startup.\n");
  654.     fprintf(stderr," -cmmem number: percentage of CM memory to use (CM code only).\n");
  655. #endif
  656.     fprintf(stderr," -v prints the version.\n");
  657.     exit(1);
  658.   }
  659.   if(NULL == (next_argument = next_arg(&argc, &argv))){
  660.     fprintf(stderr,"No arguments specified\n");
  661.     exit(0);
  662.   }
  663.   while((next_argument != NULL) &&
  664.     ('-' == next_argument[0])){
  665.  
  666.     /* then we have an argument to process */
  667.     if (0 == strcmp("-p", next_argument)){
  668.       char *peek_argument = peek_arg(&argc, &argv);
  669.       use_stdio = FALSE;
  670.       if ((NULL != peek_argument) && /* if we are not out of args */
  671.       ('-' != peek_argument[0])){ { /* and the next isn't an option... */
  672.         /* get the port number */
  673.         tcp_port = atoi(next_arg(&argc, &argv));
  674.       }         /* end if (explicit tcp_port) */
  675.                     }
  676.     }               /* end if (-p) */
  677.     else if (0 == strcmp("-s", next_argument)){
  678.       use_stdio = TRUE;
  679.     }               /* end if (-s) */
  680.  
  681.     else if (0 == strcmp("-e", next_argument)) {
  682.       char *peek_argument = peek_arg(&argc, &argv);
  683. #ifdef WIN32
  684.       log_file_name = "NUL:"; /* default to NUL: */
  685. #else
  686.       log_file_name = "/dev/null"; /* default to /dev/null */
  687. #endif
  688.       if ((peek_argument != NULL) &&
  689.       ('-' != peek_argument[0])) {
  690.     log_file_name = next_arg(&argc, &argv);
  691.       }             /* end if (explicit log file) */
  692.     }               /* end if (-e) */
  693.     else if (0 == strcmp("-l", next_argument)) {
  694.       wais_log_level = atol(next_arg(&argc, &argv));
  695.     }               /* end if (-l) */
  696.     else if (0 == strcmp("-d", next_argument)) {
  697.       index_dir = next_arg(&argc, &argv);
  698.     }
  699.     else if (0 == strcmp("-v", next_argument)) {
  700.       fprintf(stderr,"%s: %s, %s\n", command_name, VERSION, SERVER_DATE);
  701. #ifdef WIN32
  702.       fprintf(stderr,"%s\n",VERWIN32);
  703.       if (argc == 2)
  704.         exit(0);
  705. #endif 
  706.     }
  707. #ifndef WIN32
  708.     else if (0 == strcmp("-u", next_argument)) {
  709.       uid_name = next_arg(&argc, &argv);
  710.       if((uid = finduid(uid_name)) < 0)
  711.     panic("Couldn't find user %s.", uid_name);
  712.     }
  713.     else if(0 == strcmp("-cmmem", next_argument)){
  714.       if(NULL == (next_argument = next_arg(&argc, &argv)))
  715.     panic("Expected a number (1-100) for percentage of memory to use");
  716.       cm_mem_percent = atol(next_argument);
  717.       if(cm_mem_percent < 1)
  718.     panic("The -cmmem argument should not be less than 1 and less than 100");
  719.       if(cm_mem_percent > 100)
  720.     panic("Warning: The -cmmem parameter was %ld%%. It should be between 1-100.", cm_mem_percent);
  721.     }
  722. #endif
  723.     else{
  724.       panic("Don't recognize the %s option", next_argument);
  725.     }
  726.     next_argument = next_arg(&argc, &argv);
  727.   }             /* end while (more arguments) */
  728.  
  729.   if (use_stdio && log_file_name == NULL) 
  730. #ifdef WIN32
  731.     log_file_name = "NUL:";
  732. #else
  733.     log_file_name = "/dev/null";
  734. #endif
  735.   if (log_file_name == NULL) 
  736.     logfile = stderr;
  737.   else logfile = NULL;
  738.   
  739.   index_dir = index_dir ? index_dir : ".";  
  740.   info_dict = s_strdup(merge_pathnames(info_dict,index_dir));
  741.  
  742.   if(0 != init_search_engine(index_dir, false, true, cm_mem_percent,0,0))
  743.     panic("unable to initialize search engine");
  744.   
  745.   /* remember timestamp on INFO.dct if rebuilding needed 
  746.    * If it doesnt exist, it's assumed to be *very* old, to force
  747.    * re-indexing
  748.    */
  749.   info_change_time = (stat(info_dict,&statbuf) == -1) ? 0 : statbuf.st_mtime;
  750. #ifdef WIN32
  751.   /* this will replace from scandir to freedir */
  752. #ifdef NOT_NOW
  753.   /* We are not yet supporting dynamically indexing.
  754.    * It could be done by WAISINDEX tool manually.
  755.    */
  756.   if (info_change_time == 0) indexing_needed = TRUE;
  757.   if (FALSE) {
  758.  
  759.     /* Time to re-index,
  760.      * aquire the lock 
  761.      */
  762.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  763.         "re-indexing needed, info_change_time=%d",info_change_time); 
  764.  
  765.     if (GetTempPath(sizeof(LOCKFILE), LOCKFILE) == 0) {
  766.       panic("Warning - couldn't get the system temporary path %s", LOCKFILE);
  767.     }
  768.     LOCKFILE[MAX_PATH] = 0;
  769.     strcat(LOCKFILE, "\\INFO.LCK");
  770.     LOCKFILE[MAX_PATH] = 0;
  771.     if (open(LOCKFILE, _O_WRONLY|_O_CREAT|_O_EXCL,0666) == -1) {
  772.       
  773.       /* already locked by somebody else
  774.        * spin  till she finishes
  775.        */
  776.       while (!(stat(LOCKFILE,&statbuf) == -1)) {
  777.         Sleep(NAPTIME);     /* NAPTIME is 1000 millisecs, ie, 1 sec */
  778.         naptime ++;         /* in seconds */
  779.         waislog(WLOG_MEDIUM, WLOG_INFO,
  780.             "INFO locked, waiting since %d seconds", naptime);
  781.         if (naptime  > MAXNAPTIME)  {
  782.           waislog(WLOG_HIGH, WLOG_WARNING,
  783.               "Warning - lockfile %s won't go away after %d seconds, not reindexing.", 
  784.               LOCKFILE, naptime);
  785.           break;
  786.         }
  787.       }
  788.       /* if lockfile went away, assume INFO.* build finished
  789.        * so just use it
  790.        */
  791.     } else {            /* we aquired the lock, so rebuild database  */
  792.       HANDLE hSearch;
  793.       WIN32_FIND_DATA FindData;
  794.       char Name[MAX_PATH+1];
  795.       
  796.       strncpy(Name,index_dir,MAX_PATH);
  797.       Name[MAX_PATH] = '\0';
  798.       strncat(Name,"\\*.*",MAX_PATH);
  799.       Name[MAX_PATH] = '\0';
  800.       hSearch = FindFirstFile(Name,&FindData);
  801.       if (hSearch!=INVALID_HANDLE_VALUE) {
  802.         struct stat st;
  803.         char *lastdot;
  804.         int candidate;
  805.         database *db;
  806.         char *dbname;
  807.         
  808.         dbname = s_strdup(merge_pathnames("INFO", index_dir));
  809.         db = openDatabase(dbname, true, /* maybe this should append XXX */
  810.                 false);
  811.         s_free(dbname);
  812.         init_add_word(db, 0, 100000L);
  813.         
  814.         strncpy(Name, index_dir, MAX_PATH);
  815.         Name[MAX_PATH] = '\0';
  816.         if (index_dir[strlen(index_dir)-1] != '\\')
  817.           strncat(Name, "\\", MAX_PATH);
  818.         dbname = strrchr(Name, '\\');
  819.         Name[MAX_PATH] = '\0';  
  820.         if (!dbname)
  821.           panic("No path separator \\");
  822.         
  823.         while (TRUE) {
  824.           lastdot = strrchr(FindData.cFileName, '.');
  825.           candidate = lastdot && 
  826.               (stat(merge_pathnames(FindData.cFileName,index_dir), &st) >= 0) && 
  827.               ((st.st_mode & S_IFMT) == S_IFREG) &&
  828.               !strcmp(lastdot,source_ext) && 
  829.               strcmp(FindData.cFileName,info_dict); /* whew */
  830.  
  831.           if ((candidate) && (st.st_mtime > info_change_time)) {
  832.             /* do need indexing */
  833.             strncat(dbname, FindData.cFileName, MAX_PATH);
  834.             waislog(WLOG_MEDIUM, WLOG_INDEX, "Indexing %s",dbname);
  835.             index_text_file(dbname, &dataops, db, true, false, false, true);
  836.           }
  837.           
  838.           if (!FindNextFile(hSearch,&FindData)) break;
  839.         }
  840.         FindClose(hSearch);
  841.         if(!probe_file(source_filename(Name, db)))
  842.           write_src_structure(source_filename(Name, db),
  843.                   "INFO", "WSRC", NULL, 0L, true, tcp_port);
  844.         finished_add_word(db);
  845.         build_catalog(db);
  846.         closeDatabase(db);
  847.         if (unlink(LOCKFILE))
  848.           panic("Indexer: cant unlink lockfile!\n");
  849.         waislog(WLOG_MEDIUM, WLOG_INDEX, "Indexer done");
  850.       }
  851.     }
  852.   }
  853. #endif /* if NOT_NOW */
  854.  
  855. #else /* WIN32 */
  856.   /* compare with candidates */
  857.  
  858.   if (scandir(index_dir, &list, srcfiles, alphasort) < 0) {
  859.       waislog(WLOG_HIGH, WLOG_ERROR, 
  860.           "Error: reading directory %s, %s", 
  861.           index_dir, sys_errlist[errno]);
  862.       indexing_needed = FALSE;
  863.   }
  864.   
  865.   /* ok. we know if we need indexing, 
  866.    * and have all the filenames. 
  867.    */
  868.   
  869.   if (info_change_time == 0) indexing_needed = TRUE;
  870.   if (indexing_needed) {
  871.  
  872.     /* Time to re-index,
  873.      * aquire the lock 
  874.      */
  875.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  876.         "re-indexing needed, info_change_time=%d",info_change_time); 
  877.  
  878.     if (open(LOCKFILE, O_WRONLY|O_CREAT|O_EXCL,0666) == -1) {
  879.       
  880.       /* already locked by somebody else
  881.        * spin  till she finishes
  882.        */
  883.       while (!(stat(LOCKFILE,&statbuf) == -1)) {
  884.     sleep(NAPTIME);
  885.     naptime += NAPTIME;
  886.     waislog(WLOG_MEDIUM, WLOG_INFO,
  887.         "INFO locked, waiting since %d seconds", naptime);
  888.     if (naptime  > MAXNAPTIME)  {
  889.  
  890.       waislog(WLOG_HIGH, WLOG_WARNING,
  891.           "Warning - lockfile %s won't go away after %d seconds, not reindexing.", 
  892.           LOCKFILE, naptime);
  893.       break;
  894.     }
  895.       }
  896.       /* if lockfile went away, assume INFO.* build finished
  897.        * so just use it
  898.        */
  899.     } else {            /* we aquired the lock, so rebuild database  */
  900.       
  901. #ifdef INDEX_FORK
  902.       if (!(child = fork())) {
  903. #endif
  904.     database *db;
  905.     struct dirent **s = list;
  906.     char filename[MAX_FILENAME_LEN], *dbname;
  907.  
  908.     waislog(WLOG_MEDIUM, WLOG_INDEX,
  909.         "Creating INFO database, pid=%d",getpid());
  910.     dbname = s_strdup(merge_pathnames("INFO",   index_dir));
  911.     db = openDatabase(dbname, true, /* maybe this should append XXX */
  912.               false);
  913.     s_free(dbname);
  914.     init_add_word(db, 0, 100000L);
  915.  
  916.     while (*s) {        /* index it */
  917.       strncpy(filename, index_dir, MAX_FILENAME_LEN);
  918.       if(index_dir[strlen(index_dir) -1] != '/')
  919.         strncat(filename, "/", MAX_FILENAME_LEN);
  920.       strncat(filename, (*s)->d_name, MAX_FILENAME_LEN);
  921.       waislog(WLOG_MEDIUM, WLOG_INDEX,
  922.           "Indexing %s", filename);
  923.       index_text_file(filename, &dataops, db, true, false,
  924.                           false, true, NULL, NULL);
  925.           s++;
  926.         }
  927.         freedir(list);          /* array of filenames */
  928.               
  929.         if(!probe_file(source_filename(filename, db)))
  930.           write_src_structure(source_filename(filename, db),
  931.                               "INFO", "WSRC", NULL, 0L, true, tcp_port);
  932.         finished_add_word(db);
  933.         build_catalog(db);
  934.         closeDatabase(db);
  935.         if (unlink(LOCKFILE))
  936.           panic("Indexer: cant unlink lockfile!\n");
  937.         waislog(WLOG_MEDIUM, WLOG_INDEX,
  938.                 "Indexer pid=%d done", getpid());
  939.               
  940. #ifdef INDEX_FORK
  941.     exit(0);        /* indexing child */
  942.       }
  943.       else if (child == -1) {
  944.     waislog(WLOG_HIGH, WLOG_ERROR,
  945.         "Unable to fork for indexer.");
  946.     exit(1);
  947.       }
  948.       /* wait for child process */
  949.       else while (wait(0) != child) ; /* do nothing */
  950. #endif 
  951.      
  952.     }
  953.   }
  954. #endif /* WIN32 */
  955.  
  956.  
  957.   if (use_stdio == TRUE) {
  958.     if(host_address[0] != 0){
  959.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  960.           "Accepted connection from: %s [%s], %s",
  961.           host_name, host_address, VERSION);
  962.     }
  963.     else{
  964.       waislog(WLOG_MEDIUM, WLOG_CONNECT,
  965.           "Couldn't determine peer connection. %s", VERSION);
  966.     }
  967.  
  968.     if ( server_security(index_dir,NULL) != true ){
  969.       waislog(WLOG_HIGH, WLOG_INFO,"Closing down server");
  970.       exit(-1);
  971.      }
  972.  
  973.   }
  974.   else{
  975.     waislog(WLOG_MEDIUM, WLOG_INFO, "Running server %s", VERSION);
  976.   }
  977.  
  978. #ifndef WIN32
  979.   signal(SIGINT, (void *)breakKey);
  980.  
  981.   signal(SIGCHLD, childhandler);    /* XXX dont really need this any more */
  982.   signal(SIGALRM, alarmhandler);
  983.  
  984.   signal(SIGSEGV, seghandler);
  985.  
  986.   signal(SIGBUS, bushandler);
  987.  
  988.  
  989.   if(use_stdio == FALSE)
  990.    { 
  991.      if (tcp_port < 1024 && getuid() != 0) {
  992.        waislog(WLOG_HIGH, WLOG_ERROR,
  993.            "Error opening port %d:  Must be superuser to use a port < 1024",
  994.            tcp_port);
  995.        exit(-1);
  996.      }
  997.  
  998.      open_server(tcp_port,&socket,BUFSZ);
  999.  
  1000. #ifdef SECURE_SERVER
  1001.      /* if root, setuid to user specified id. */
  1002.      if (uid > 0 && getuid() == 0)  {
  1003.        waislog(WLOG_MEDIUM, WLOG_INFO,
  1004.            "Setting uid to %s.", uid_name);
  1005.         if (log_file_name && *log_file_name &&
  1006.        chown(log_file_name,uid,getgid()) < 0)
  1007.      waislog(WLOG_HIGH, WLOG_ERROR,
  1008.          "Unable to chown log file to %s!", uid_name);
  1009.        if ( 0 > setuid(uid)) {
  1010.      waislog(WLOG_HIGH, WLOG_ERROR,
  1011.          "Unable to setuid to %s!  Exiting.", uid_name);
  1012.      exit(-1);
  1013.        }
  1014.      }
  1015. #endif
  1016.      while (TRUE) { /* be a server for several connections */
  1017.        accept_client_connection(socket,&file);
  1018.       
  1019.        if ((child_proc = fork()) == 0) {
  1020.           
  1021.           /* grandson handles this connection
  1022.            * double-fork takes care of zombies 
  1023.            */
  1024.           if ((child_proc = fork()) == 0) { 
  1025.         wais_pid = getpid();
  1026.         log_line = 0;
  1027.         serve_client(file, file, index_dir);
  1028.         /* but leaves server up */
  1029.         close_client_connection(file);
  1030.         close_server(socket);
  1031.         /* just exits this child */
  1032.         waislog(WLOG_MEDIUM, WLOG_CLOSE,
  1033.             "Done handling client");
  1034.         exit(0);
  1035.           } else {
  1036.         /* son: orphans the grandchild, so init picks up 
  1037.          * the exit status
  1038.          */
  1039.         exit(0);
  1040.           }
  1041.           } else {
  1042.           waislog(WLOG_MEDIUM, WLOG_INFO,
  1043.               "Child PID = %d", child_proc);
  1044.           close_client_connection(file);     /* parent shouldn't keep the file */
  1045.       }
  1046.       }
  1047.    }
  1048.   else if(use_stdio == TRUE)
  1049. #else
  1050.   if(use_stdio == TRUE)
  1051. #endif /* !WIN32 */
  1052.    { /* connections on stdio don't use child processes yet */
  1053.      serve_client(stdin, stdout, index_dir);
  1054.      waislog(WLOG_MEDIUM, WLOG_CLOSE,
  1055.          "Done handling client");
  1056.       /* close the whole thing */
  1057.      if(0 != finished_search_engine())
  1058.        panic("unable to close search engine");
  1059.      exit(0);
  1060.    }
  1061. }
  1062.  
  1063. /*---------------------------------------------------------------------------*/
  1064.  
  1065.